/* This file is my contribution for Clementine.
   Copyright 2012, Andrey Semenov <semenoff.andrew@gmail.com>

   Clementine is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   Clementine is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with Clementine.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "vkservice.h"

#include <QDesktopServices>
#include <QMenu>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QTimer>

#include <qjson/parser.h>
#include <qjson/serializer.h>

#include "internetmodel.h"
#include "searchboxwidget.h"

#include "core/application.h"
#include "core/closure.h"
#include "core/logging.h"
#include "core/mergedproxymodel.h"
#include "core/network.h"
#include "core/song.h"
#include "core/taskmanager.h"
#include "core/timeconstants.h"
#include "core/utilities.h"
#include "globalsearch/globalsearch.h"
#include "ui/iconloader.h"

#include <vreen/client.h>
#include <vreen/roster.h>
#include <vreen/auth/oauthconnection.h>

const int VkService::kApiClientId = 3237615;

const char* VkService::kServiceName = "VK";
const char* VkService::kSettingsGroup = "VK";
const char* VkService::kUrl = "http://vk.com/";
const char* VkService::kHomepage = "http://vk.com/";

const int VkService::kSearchDelayMsec = 400;
const int VkService::kSongSearchLimit = 100;
const int VkService::kSongSimpleSearchLimit = 10;

typedef QPair<QString, QString> Param;



VkService::VkService(Application* app, InternetModel *parent)
  : InternetService(kServiceName, app, parent, parent),        
    root_(NULL),    
    search_(NULL),
    //network_(new NetworkAccessManager(this)),
    context_menu_(NULL),
    search_box_(new SearchBoxWidget(this)),
    search_delay_(new QTimer(this)),
    next_pending_search_id_(0),
    provider_(NULL){

  search_delay_->setInterval(kSearchDelayMsec);
  search_delay_->setSingleShot(true);
  connect(search_delay_, SIGNAL(timeout()), SLOT(DoSearch()));
  connect(search_box_, SIGNAL(TextChanged(QString)), SLOT(Search(QString)));
}


VkService::~VkService() {
}


QStandardItem* VkService::CreateRootItem() {
  root_ = new QStandardItem(QIcon(":providers/vk.png"), kServiceName);
  root_->setData(true, InternetModel::Role_CanLazyLoad);
  // root_->setData(InternetModel::PlayBehaviour_DoubleClickAction,InternetModel::Role_PlayBehaviour);
  return root_;
}

void VkService::LazyPopulate(QStandardItem* item) {
  switch (item->data(InternetModel::Role_Type).toInt()) {
    case InternetModel::Type_Service: {
      EnsureItemsCreated();
      mymusic_ = new QStandardItem(tr("My Music"));
      mymusic_->setToolTip(tr("Music from your vk.com profile"));
      mymusic_->setData(InternetModel::PlayBehaviour_MultipleItems,
                       InternetModel::Role_PlayBehaviour);
      root_->appendRow(mymusic_);
      InitProvider();
      break;
    }
    default:
      break;
  }
}

void VkService::InitProvider() {
  if (!provider_){ //If it the first request, then we need to connect to vk.com
    Vreen::OAuthConnection * auth = new Vreen::OAuthConnection(kApiClientId, this);
    auth->setConnectionOption(Vreen::Connection::ShowAuthDialog, true); //Will show OAuth login window
    auth->setConnectionOption(Vreen::Connection::KeepAuthData, true); //We don't want to see it every time we search

    Vreen::Client * client_=new Vreen::Client(this);

    uid_=client_->roster()->uid();
    client_->setConnection(auth);
    connect(client_, SIGNAL(onlineStateChanged(bool)), SLOT(LoadMyMusic()));
    provider_=new Vreen::AudioProvider(client_);
    client_->connectToHost();
    	
  }
}

void VkService::EnsureItemsCreated() {
  search_ = new QStandardItem(IconLoader::Load("edit-find"),
                              tr("Search results"));
  search_->setToolTip(tr("Start typing something on the search box above to "
                         "fill this search results list"));
  search_->setData(InternetModel::PlayBehaviour_MultipleItems,
                   InternetModel::Role_PlayBehaviour);
  root_->appendRow(search_);
}

QWidget* VkService::HeaderWidget() const {
  return search_box_;
}

void VkService::Homepage() {
  QDesktopServices::openUrl(QUrl(kHomepage));
}

void VkService::Search(const QString& text, bool now) {
  pending_search_ = text;

  // If there is no text (e.g. user cleared search box), we don't need to do a
  // real query that will return nothing: we can clear the playlist now
  if (text.isEmpty()) {
    search_delay_->stop();
    ClearSearchResults();
    return;
  }

  if (now) {
    search_delay_->stop();
    DoSearch();
  } else {
    search_delay_->start();
  }  
}

void VkService::LoadMyMusic() { //Requests songs from 'My music' page on vk.com
  Vreen::AudioItemListReply * reply=provider_->getContactAudio(uid_);
  const int id = next_pending_search_id_++;
  NewClosure(reply, SIGNAL(resultReady(const QVariant&)),
             this, SLOT(LoadMyMusicFinished(Vreen::AudioItemListReply*,int)),
             reply, id);
}

void VkService::DoSearch() { //Searches songs on vk.com
  ClearSearchResults();

  Vreen::AudioItemListReply * reply=provider_->searchAudio(pending_search_);
  const int id = next_pending_search_id_++;
  NewClosure(reply, SIGNAL(resultReady(const QVariant&)),
             this, SLOT(SearchFinished(Vreen::AudioItemListReply*,int)),
             reply, id);
}

void VkService::LoadMyMusicFinished(Vreen::AudioItemListReply* reply, int task_id) {
  reply->deleteLater();

  SongList songs = ExtractSongs(reply);
  // Fill results list
  foreach (const Song& song, songs) {
    QStandardItem* child = CreateSongItem(song);
    mymusic_->appendRow(child);
  }

  QModelIndex index = model()->merged_model()->mapFromSource(mymusic_->index());
  ScrollToIndex(index);
}

void VkService::SearchFinished(Vreen::AudioItemListReply* reply, int task_id) {
  reply->deleteLater();

  SongList songs = ExtractSongs(reply);
  // Fill results list
  foreach (const Song& song, songs) {
    QStandardItem* child = CreateSongItem(song);
    search_->appendRow(child);
  }

  QModelIndex index = model()->merged_model()->mapFromSource(search_->index());
  ScrollToIndex(index);
}

void VkService::ClearSearchResults() {
  if (search_)
    search_->removeRows(0, search_->rowCount());
}

void VkService::EnsureMenuCreated() {
  if(!context_menu_) {
    context_menu_ = new QMenu;
    context_menu_->addActions(GetPlaylistActions());
    context_menu_->addSeparator();
    context_menu_->addAction(IconLoader::Load("download"),
                             tr("Open %1 in browser").arg("vk.com"),
                             this, SLOT(Homepage()));
  }
}

void VkService::ShowContextMenu(const QPoint& global_pos) {
  EnsureMenuCreated();
  
  context_menu_->popup(global_pos);
}


SongList VkService::ExtractSongs(Vreen::AudioItemListReply* reply) {
  SongList songs;

  Vreen::AudioItemList q_audio_list = reply->result();

  foreach(const Vreen::AudioItem q, q_audio_list) {
    Song song = ExtractSong(q);
    if (song.is_valid()) {
      songs << song;
    }
  }
  return songs;
}

Song VkService::ExtractSong(const  Vreen::AudioItem& result_song) {
  Song song;
  song.set_url(result_song.url());

  song.set_artist(result_song.artist());
  song.set_title(result_song.title());

  quint64 duration = (quint64)result_song.duration()* kNsecPerMsec*1000;
  song.set_length_nanosec(duration);

  song.set_valid(true);

  return song;
}
